#ifndef QUEUE_H
#define QUEUE_H

#include "..\app_cfg.h"

#define QUEUE_NAME(__NAME)  __NAME##_queue_t

#define DEF_QUEUE(__NAME, __TYPE)                           \
    typedef struct __##__NAME##_queue_t __NAME##_queue_t;   \
    struct __##__NAME##_queue_t {                           \
        uint8_t chHead;                                     \
        uint8_t chTail;                                     \
        uint8_t chSize;                                     \
        uint8_t chLength;                                   \
        __TYPE *ptBuf;                                      \
    };                                                      \
                                                            \
    __QUEUE_INIT(__NAME, __TYPE)                            \
    __QUEUE_IN(__NAME, __TYPE)                              \
    __QUEUE_OUT(__NAME, __TYPE)                             \
    __QUEUE_IS_EMPTY(__NAME)

#define END_DEF_QUEUE(__NAME)

#define __QUEUE_INIT(__NAME, __TYPE)                                    \
    bool __NAME##_queue_init(__NAME##_queue_t* ptQueue, __TYPE* ptBuffer, uint8_t size) \
    {                                                                   \
        if ((ptQueue == NULL) || (ptBuffer == NULL) || (size == 0)) {   \
            return false;                                               \
        }                                                               \
        ptQueue->ptBuf = ptBuffer;                                      \
        ptQueue->chSize = size;                                         \
        ptQueue->chHead = 0;                                            \
        ptQueue->chTail = 0;                                            \
        ptQueue->chLength = 0;                                          \
                                                                        \
        return true;                                                    \
    }

#define __QUEUE_IN(__NAME, __TYPE)                                      \
    bool __NAME##_in(__NAME##_queue_t* ptQueue, __TYPE* ptVal)          \
    {                                                                   \
        if ((ptQueue == NULL) || (ptVal == NULL)) {                     \
            return false;                                               \
        }                                                               \
                                                                        \
        __NAME##_queue_t* ptQ = (__NAME##_queue_t*)ptQueue;             \
        if (ptQ->chLength < ptQ->chSize) {                              \
            ptQ->chLength++;                                            \
            ptQ->ptBuf[ptQ->chTail] = *ptVal;                           \
            if (ptQ->chTail == (ptQ->chSize - 1)) {                     \
                ptQ->chTail = 0;                                        \
            } else {                                                    \
                ptQ->chTail++;                                          \
            }                                                           \
            return true;                                                \
        }                                                               \
        return false;                                                   \
    }

#define __QUEUE_OUT(__NAME, __TYPE)                                     \
    bool __NAME##_out(__NAME##_queue_t* ptQueue, __TYPE* ptVal)         \
    {                                                                   \
        if ((ptQueue == NULL) || (ptVal == NULL)) {                     \
            return false;                                               \
        }                                                               \
                                                                        \
        __NAME##_queue_t* ptQ = (__NAME##_queue_t*)ptQueue;             \
        if (ptQ->chLength) {                                            \
            ptQ->chLength--;                                            \
            *ptVal = ptQ->ptBuf[ptQ->chHead];                           \
            if (ptQ->chHead == (ptQ->chSize - 1)) {                     \
                ptQ->chHead = 0;                                        \
            } else {                                                    \
                ptQ->chHead++;                                          \
            }                                                           \
            return true;                                                \
        }                                                               \
        return false;                                                   \
    }

#define __QUEUE_IS_EMPTY(__NAME)                                        \
    bool __NAME##_is_empty(__NAME##_queue_t* ptQueue)                   \
    {                                                                   \
        if (ptQueue == NULL) {                                          \
            return false;                                               \
        }                                                               \
                                                                        \
         return 0 == ptQueue->chLength;                                 \
    }

#endif
